package com.st.mongodb;

import com.mongodb.BasicDBObject;
import com.mongodb.Block;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.ServerAddress;
import com.mongodb.WriteResult;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.mongodb.util.JSON;

import org.bson.Document;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Locale;

import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.eq;
import static com.mongodb.client.model.Filters.gt;
import static com.mongodb.client.model.Filters.or;
import static com.mongodb.client.model.Sorts.ascending;
import static java.util.Arrays.asList;

/**
 * @author wuxianwei on 15/11/24.
 */
public class GettingStarted {
  public static void main(String[] args) throws ParseException {
    //java Driver
    MongoClient mongoClient = new MongoClient();
    MongoClient mongoClient2 = new MongoClient("localhost", 27017);
    MongoClient mongoClient4 = new MongoClient(new ServerAddress("localhost", 27017));
    MongoClient mongoClientCluster = new MongoClient(Arrays.asList(
            new ServerAddress("localhost", 27017),
            new ServerAddress("localhost", 27018),
            new ServerAddress("localhost", 27019)));

    MongoDatabase db = mongoClient.getDatabase("test");
    db.runCommand(new Document("",""));

    //如何把json数据直接插入 时间类型并不能被转换
    //过时的方式
    DB db2 = mongoClient.getDB("test");
    DBCollection coll = db2.getCollection("restaurants");
    String jsonString = "{\"address\":{\"building\":\"1480\",\"coord\":[-73.9557413,40.7720266],\"street\":\"2 Avenue\",\"zipcode\":\"10075\"},\"borough\":\"Manhattan\",\"cuisine\":\"Italian\",\"grades\":[{\"date\":\"2014-10-01T00:00:00Z\",\"grade\":\"A\",\"score\":11},{\"date\":\"2014-01-16T00:00:00Z\",\"grade\":\"B\",\"score\":17}],\"name\":\"Vella\",\"restaurant_id\":\"41704620\"}";
    DBObject doc = (BasicDBObject) JSON.parse(jsonString);
    WriteResult writeResult = coll.insert(doc);
    System.out.println(writeResult.getN());

    //insert Data
    Document myDoc = Document.parse(jsonString);
    System.out.println(myDoc.toJson());
    db.getCollection("restaurants").insertOne(myDoc);

    DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH);
    db.getCollection("restaurants").insertOne(
            new Document("address",
                    new Document()
                            .append("street", "2 Avenue")
                            .append("zipcode", "10075")
                            .append("building", "1480")
                            .append("coord", asList(-73.9557413, 40.7720266)))
                    .append("borough", "Manhattan")
                    .append("cuisine", "Italian")
                    .append("grades", asList(
                            new Document()
                                    .append("date", format.parse("2014-10-01T00:00:00Z"))
                                    .append("grade", "A")
                                    .append("score", 11),
                            new Document()
                                    .append("date", format.parse("2014-01-16T00:00:00Z")) //直接是date类型
                                    .append("grade", "B")
                                    .append("score", 17)))
                    .append("name", "Vella")
                    .append("restaurant_id", "41704620"));

    //find or query data
    FindIterable<Document> iterable = db.getCollection("restaurants").find();
    iterable.forEach(new Block<Document>() {
      @Override
      public void apply(final Document document) {
        System.out.println(document);
      }
    });
    iterable.forEach((Block<Document>) document -> {
      System.out.println(document);
    });
    iterable.forEach((Block<Document>) System.out::println);


    FindIterable<Document> iterableEqual = db.getCollection("restaurants").find(
            new Document("borough", "Manhattan"));
    FindIterable<Document> iterableEmbedded = db.getCollection("restaurants").find(
            new Document("address.zipcode", "10075")); //嵌套的 和数组 都是这样写
    FindIterable<Document> iterableOperator = db.getCollection("restaurants").find(
            new Document("grades.score", new Document("$gt", 30)));
    FindIterable<Document> iterableAnd = db.getCollection("restaurants").find(
            new Document("cuisine", "Italian").append("address.zipcode", "10075"));
    FindIterable<Document> iterableOr = db.getCollection("restaurants").find(
            new Document("$or", asList(new Document("cuisine", "Italian"),
                    new Document("address.zipcode", "10075"))));
    FindIterable<Document> iterableSort = db.getCollection("restaurants").find().limit(0).skip(0).sort(new Document("borough", 1).append("address.zipcode", 1));//limit skip 用法类似
    //Using the static Filters helper(s), you can also specify the query as follows:
    FindIterable<Document> iterableEqual2 = db.getCollection("restaurants").find(eq("borough", "Manhattan"));
    FindIterable<Document> iterableEmbedded2 = db.getCollection("restaurants").find(eq("address.zipcode", "10075"));
    FindIterable<Document> iterableOperator2 = db.getCollection("restaurants").find(gt("grades.score", 30));
    FindIterable<Document> iterableAnd2 = db.getCollection("restaurants").find(and(eq("cuisine", "Italian"), eq("address.zipcode", "10075")));
    FindIterable<Document> iterableOr2 = db.getCollection("restaurants").find(or(eq("cuisine", "Italian"), eq("address.zipcode", "10075")));
    FindIterable<Document> iterableSort2 = db.getCollection("restaurants").find().sort(ascending("borough", "address.zipcode"));

    iterableEqual.forEach(new Block<Document>() {
      @Override
      public void apply(Document document) {
        System.out.println(document);
      }
    });

    //Update Top-Level Fields
    db.getCollection("restaurants").updateOne(new Document("name", "Juni"),
            new Document("$set", new Document("cuisine", "American (New)"))
                    .append("$currentDate", new Document("lastModified", true)));
    //Update an Embedded Field
    db.getCollection("restaurants").updateOne(new Document("restaurant_id", "41156888"),
            new Document("$set", new Document("address.street", "East 31st Street")));

    //Update Multiple Documents
    UpdateResult updateResult = db.getCollection("restaurants").updateMany(new Document("address.zipcode", "10016").append("cuisine", "Other"),
            new Document("$set", new Document("cuisine", "Category To Be Determined"))
                    .append("$currentDate", new Document("lastModified", true)));
    System.out.println(updateResult.getModifiedCount());
    //Replace a Document After the update, the document only contains the field or fields in the replacement document.
    db.getCollection("restaurants").replaceOne(new Document("restaurant_id", "41704620"),
            new Document("address",
                    new Document()
                            .append("street", "2 Avenue")
                            .append("zipcode", "10075")
                            .append("building", "1480")
                            .append("coord", asList(-73.9557413, 40.7720266)))
                    .append("name", "Vella 2"));

    //Remove All Documents That Match a Condition
    DeleteResult deleteResult = db.getCollection("restaurants").deleteMany(new Document("borough", "Manhattan"));
    System.out.println(deleteResult.getDeletedCount());
    //remove all documents
    db.getCollection("restaurants").deleteMany(new Document());
    //drop a collection
    db.getCollection("restaurants").drop();

    //Group Documents by a Field and Calculate Count
    AggregateIterable<Document> iterableGroup = db.getCollection("restaurants").aggregate(asList(
            new Document("$group", new Document("_id", "$borough").append("count", new Document("$sum", 1)))));
    iterableGroup.forEach(new Block<Document>() {
      @Override
      public void apply(final Document document) {
        System.out.println(document.toJson());
      }
    });

    //Filter and Group Documents
    AggregateIterable<Document> iterableFilter = db.getCollection("restaurants").aggregate(asList(
            new Document("$match", new Document("borough", "Queens").append("cuisine", "Brazilian")),
            new Document("$group", new Document("_id", "$address.zipcode").append("count", new Document("$sum", 1)))));
    iterableFilter.forEach((Block<Document>) document -> {
      System.out.println(document.toJson());
      document.toJson();
    });

    //Create Index
    String indexName = db.getCollection("restaurants").createIndex(new Document("cuisine", 1));
    System.out.println(indexName);
    //The index orders its entries first by ascending "cuisine" values, and then, within each "cuisine", by descending "address.zipcode" values.
    db.getCollection("restaurants").createIndex(new Document("cuisine", 1).append("address.zipcode", -1));

  }
}
